/*
 * AbstractLayer.h
 *
 *  Created on: 2010-9-26
 *      Author: wenjian
 */

#ifndef ABSTRACTLAYER_H_
#define ABSTRACTLAYER_H_
#include "../commons.h"
#include <event/EventListener.h>
#include "ddatatypes.h"
#include "eventtypes.h"
#include "VisibleSupport.h"
#include "ModifiedSupport.h"
#include "ModifiedEvent.h"
#include "MouseEvent.h"
#include "KeyEvent.h"
#include "CursorSupport.h"
#include "Cursor.h"
#include "EventSupport.h"
#include "SelectEvent.h"
#include "MoveSupport.h"
#include "AbstractElements.h"
#include "AbstractSelection.h"
#include "PaintEvent.h"

namespace Ed {
  class AbstractDrawPage;
  class AbstractElement;

  class AbstractLayer :
    public VisibleSupport,
    public ModifiedSupport,
    public Thk::EventListener,
    public EventSupport,
    public CursorSupport,
    public MoveSupport{

    friend class AbstractDrawPage;
    friend class AbstractElement;

    public:
      AbstractLayer(AbstractDrawPage* page, AbstractSelection* selct);
      virtual ~AbstractLayer();

      /**
       * 设置层相对画布位置(x,y)坐标，宽度，高度
       */
      //virtual void setGeometry(real x, real y, real w, real h)=0;
      virtual void setGeometry(real x, real y, real w, real h){
        return;
      }

      /**
       * 检查是否包含点(x, y)
       */
      //virtual bool intersects(real x, real y)=0;
      virtual bool intersects(real x, real y){
        return false;
      }

      /**
       * 返回相对于画布的x坐标
       */
      virtual inline real x() const {
        return 0;
      }
      /**
       * 返回相对于画布的y坐标
       */
      virtual inline real y() const {
        return 0;
      }
      /**
       * 返回宽度
       */
      virtual real width() const;
      /**
       * 返回高度
       */
      virtual real height() const;

      /**
       * 设置图层被修改状态
       */
      virtual void setModified(bool b);


      /**
       * 处理层内元素ModifiedEvent事件, 向层添加元素时，
       * 会自动向元素添加ModifiedEvent事件监听器
       */
      virtual bool handle(const Thk::Event* e);

      /**
       * 加入元素, 也可用于调整元素位置, 如果元素已经存在，将调整层次位置
       */
      virtual void addElement(AbstractElement* e, int pos);

      /**
       * 加入元素
       */
      virtual inline void addElement(AbstractElement* e) {
        addElement(e, elements.size());
      }

      /**
       * 加入元素
       */
      virtual inline void addElements(const std::vector<AbstractElement*>* els, int pos) {
        std::vector<AbstractElement*>::const_iterator it = els->begin();
        for(; it != els->end(); it++){
          addElement(*it, pos);
        }
      }

      /**
       * 加入元素
       */
      virtual inline void addElements(const std::vector<AbstractElement*>* els) {
        addElements(els, elements.size());
      }

      /**
       * 调整元素位置,target为目标参照元素，indexBy小于等于0，调整到在目标元素之前
       * （底层方向），大于0调整到目标元素之后(顶层方向), 如果不指定目标参照元素，默认为自己
       */
      virtual void adjustElement(AbstractElement* e, int indexBy, AbstractElement* target=NULL);

      /**
       * 移除元素, 同时清除鼠标悬停元素，焦点元素，监听器
       */
      virtual bool removeElement(AbstractElement* e);

      /**
       * 对ordereds中中元素排序，排序规则与元素在层中的顺序一致
       */
      virtual void sortElements(std::vector<AbstractElement*>* ordereds);


      /**
       * 在outOrdereds中返回inOrdereds被排序后的元素，排序规则与元素在层中的顺序一致
       */
      virtual void sortElements(std::vector<AbstractElement*>* outOrdereds, const std::vector<AbstractElement*>* inOrdereds);


      /**
       * 清除所有元素
       */
      virtual inline void clear() {
        //设置层被修改状态
        setModified(true);
        return elements.clear();
      }

      /**
       * 返回指定坐标 x,y上的最顶层可视元素, 如果没有，返回NULL
       *
       * @param x X坐标
       * @param y Y坐标
       * @param excluded 被排除的元素
       *
       */
      virtual AbstractElement* find(real x, real y, const AbstractElement* excluded = NULL);

      /**
       * 返回层中所有元素
       */
      virtual inline const std::vector<AbstractElement*>* getAbstractElements() const{
        return elements.getAbstractElements();
      }

      /**
       * 返回层中指定元素位置
       */
      virtual inline int getIndex(AbstractElement* e){
        return elements.getIndex(e);
      }

      /**
       * 返回DrawPage
       */
      virtual inline AbstractDrawPage* getDrawPage() const{
        return drawPage;
      }

      /**
       * 设置此层所属画布
       */
      virtual inline void setDrawPage(AbstractDrawPage* page) {
        drawPage = page;
      }

      /**
       * 设置鼠标事件响应模式
       */
      virtual inline void setMouseEventMode(MouseEventMode mode, AbstractElement* e=NULL){
        mouseEventMode = mode;
        //mouseHoveringElement = e;
        manualModeElement = e;
      }

      /**
       * 返回鼠标事件响应模式
       */
      virtual inline MouseEventMode getMouseEventMode(){
        return mouseEventMode;
      }

      /**
       * 返回鼠标事件响应元素
       */
      virtual inline AbstractElement* getMouseHoveringElement(){
        return mouseHoveringElement;
      }

      /**
       * 返回指定元素模式元素
       */
      virtual inline AbstractElement* getManualModeElement(){
        return manualModeElement;
      }

      /**
       * 清除鼠标悬停元素
       */
      virtual inline void clearMouseHoveringElement(){
        mouseHoveringElement = NULL;
      }

      /**
       * 检查鼠标是否正停在此层上面
       */
      virtual inline bool mouseIsHovering(){
        return mouseHovering;
      }

      /**
       * 返回选择器
       */
      virtual inline AbstractSelection* getAbstractSelection(){
        return selection;
      }

      /**
       * 设置焦点
       */
      virtual void setFocus();

      /**
       * 检查是否焦点层
       */
      virtual bool isFocus();

      /**
       * 可能会返回NULL
       */
      virtual inline AbstractElement* getFocusElement(){
        return focusElement;
      }

      /**
       * 设置焦点元素
       */
      virtual inline void setFocusElement(AbstractElement* e){
        focusElement = e;
      }

      /**
       * 增量移动到目标位置
       */
      virtual inline void moveBy(real dx, real dy){
        setGeometry(this->x()+dx, this->y()+dy, width(), height());
      }

      /**
       * 设置层中元素绘制模式
       */
      virtual inline void setDrawMode(DrawMode dm){
        drawMode = dm;
      }

      /**
       * 返回层中元素绘制模式
       */
      virtual inline DrawMode getDrawMode(){
        return drawMode;
      }

      /**
       * 设置此层是否响应事件
       */
      virtual inline void setEventEnabled(bool e){
        eventEnabled = e;
      }

      /**
       * 检查此层是否响应事件
       */
      virtual inline bool isEventEnabled(){
        return eventEnabled;
      }

      /**
       * 跟踪响应事件, 向层或元素传递鼠标、键盘或其它事件
       */
      virtual bool trackEvent(const Thk::Event* e);


      /**
       * 返回最近一次绘制元素的数量
       */
      virtual int getDrawElementCount(){
        return drawedCount;
      }

      /**
       * 返回最近一次绘制层使用时间，毫秒
       */
      virtual long getDrawSpendTime(){
        return spendTime;
      }

    private:
      /**
       * 处理鼠标事件
       */
      bool handleMouseEvent(const MouseEvent* me);
      /**
       * 返回指定坐标 x,y上的最顶层可视并能响应事件的元素, 如果没有，返回NULL
       *
       * @param x X坐标
       * @param y Y坐标
       * @param excluded 被排除的元素
       */
      AbstractElement* findByEventEnabled(real x, real y);

      /**
       *事件跟踪到元素
       */
      bool elementTrackEvent(AbstractElement* el, const MouseEvent* me);

      /**
       * 发送鼠标离开层事件
       */
      bool mouseLeave();

      /**
       * 发送鼠标进入层事件
       */
      bool mouseEnter();

//      /**
//       * 鼠标离开元素
//       */
//      void mouseLeaveElement(AbstractElement* e);

    protected:

      /**
       * 调用e的throwPaintEvent方法抛出PaintEvent事件
       */
      void throwPaintEvent(AbstractElement* e);

    protected:
      //绘画页
      AbstractDrawPage* drawPage;
      //此层中所有元素
      AbstractElements elements;
      //鼠标正在此层上移动时，设置此悬停状态标记
      bool mouseHovering;

      //定义鼠标移出事件
      MouseEvent mLeaveEvent;
      //定义鼠标移入事件
      MouseEvent mEnterEvent;

      //鼠标事件响应模式
      MouseEventMode mouseEventMode;
      //鼠标事件响应元素
      AbstractElement* mouseHoveringElement;
      //MEventMode_Manual模式下指定元素
      AbstractElement* manualModeElement;
      //选择器
      AbstractSelection* selection;
      //当前焦点元素
      AbstractElement* focusElement;
      //定义改变被修改状态事件
      ModifiedEvent modifiedEvent;
      //元素绘制模式
      DrawMode drawMode;
      //是否能响应事件
      bool eventEnabled;
      //定义绘制层事件
      PaintEvent paintEvent;
      //最近一次绘制元素的数量
      int drawedCount;
      //最近一次绘制层用时，单位：毫秒
      long spendTime;

  };

}

#endif /* ABSTRACTLAYER_H_ */
